﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

using CronusModel;

namespace Cronus.ViewModel.Data
{
    public class Project
    {
        //*** Constants ***//
        //*** Static ***//
        //*** Member Variables ***//
        private CronusData.ProjectsRow _ProjectRow;

        //*** Properties ***//
        public string ProjectName
        {
            get { return _ProjectRow.Name; }
            set { _ProjectRow.Name = value; }
        }

        public IEnumerable<Task> Tasks
        {
            get { return GetAssociatedTasks(); }
        }

        internal CronusData DataSet
        {
            get { return (CronusData)_ProjectRow.Table.DataSet; }
        }

        internal CronusData.ProjectsRow ProjectRow
        {
            get { return _ProjectRow; }
        }

        //*** Events ***//
        //*** Constructors ***//
        internal Project(CronusData.ProjectsRow aProjectRow)
        {
            _ProjectRow = aProjectRow;
        }

        //*** Abstract Methods ***//
        //*** Methods ***//
        /// <summary>
        /// Returns an ObservableCollection of Task objects associated with this project.
        /// </summary>
        /// <returns>ObjservableCollection of Task objects associated with this Project.</returns>
        private IEnumerable<Task> GetAssociatedTasks()
        {
            // Query for the task row objects, add them as data adapters to the collection.
            return from aTask in DataSet.Tasks
                   where aTask.Name == ProjectName
                   select new Task(aTask);
        }

        /// <summary>
        /// Create a new Project with the given name.  Also creates an associated Task with the
        /// same name as the Project.  If the Project already exists, a pointer to the existing
        /// Project is returned.
        /// </summary>
        /// <param name="strProjectName">Name to call the Project.</param>
        /// <returns>Instance of the Project requested.</returns>
        public static Project Create(DataModel aDataModel, string strProjectName)
        {
            Project aProject = null;

            QueryProjectInformation aProjectQuery = new QueryProjectInformation(aDataModel);
            if (aProjectQuery.DoesProjectAlreadyExist(strProjectName))
            {
                aProject = aProjectQuery.GetProjectWithName(strProjectName);
            }
            else // Project doesn't already exist, create a new one
            {
                // Create the new project
                CronusData.ProjectsRow aNewProject = aDataModel.ProjectsTable.NewProjectsRow();
                aNewProject.Name = strProjectName;
                aDataModel.ProjectsTable.AddProjectsRow(aNewProject);

                // Create a starting task to accompany the project.
                CronusData.TasksRow aNewTask = aDataModel.TasksTable.NewTasksRow();
                aNewTask.Name = strProjectName;
                aNewTask.ProjectsRow = aNewProject; // Link the Task and Project together.
                aDataModel.TasksTable.AddTasksRow(aNewTask);

                // Create an adapter to return to the user
                aProject = new Project(aNewProject);
            }
            return aProject;
        }

        /// <summary>
        /// Deletes this project and all associated tasks and activites.
        /// </summary>
        internal void Delete()
        {
            while (Tasks.Any())
                Tasks.FirstOrDefault().Delete();

            ProjectRow.Delete();
        }

        /// <summary>
        /// If the tasks exist, associates them with the given project.
        /// </summary>
        /// <param name="dataModel"></param>
        /// <param name="project"></param>
        /// <param name="tasksToAssociate"></param>
        public static void AssociateTasksWithProject(DataModel dataModel, Project project, IEnumerable<string> tasksToAssociate)
        {
            foreach (var taskName in tasksToAssociate)
            {
                // Search for the task. If it exists, associate it with the project.
                var task = dataModel.Tasks.FirstOrDefault(t => t.TaskName == taskName);
                if (null != task)
                    task.Project = project;
            }
        }

        /// <summary>
        /// If the tasks are associated with the given project, removes the assoication from them.
        /// </summary>
        /// <param name="project"></param>
        /// <param name="tasksToRemove"></param>
        public static void DisassociateTasksFromProject(Project project, IEnumerable<string> tasksToRemove)
        {
            // Look for each task to remove the association from and if it is part of the given project, remove the association.
            foreach (var taskName in tasksToRemove)
            {
                var task = project.Tasks.FirstOrDefault(t => t.TaskName == taskName);
                if (null != task)
                    task.Project = null;
            }
        }

        /// <summary>
        /// Renames the given project with the new name.
        /// </summary>
        /// <param name="project">Project to rename.</param>
        /// <param name="newName">Cannot be empty or null.</param>
        public static void Rename(Project project, string newName)
        {
            if (!String.IsNullOrEmpty(newName))
                project.ProjectName = newName;
        }
    }
}
